package com.sixbro.resource.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;

import java.io.Serializable;
import java.util.Optional;

import static java.util.Collections.emptyList;

/**
 * <p>
 *
 * </p>
 *
 * @author: Mr.Lu
 * @since: 2021/11/2 16:32
 */
public class DefaultPermissionEvaluator implements PermissionEvaluator {
    private final Logger logger = LoggerFactory.getLogger( DefaultPermissionEvaluator.class );

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if ( authentication == null || targetDomainObject == null || !( permission instanceof String ) ) {
            return false;
        }
        String targetType = targetDomainObject.toString( );
        if ( !( targetDomainObject instanceof String ) ) {
            targetType = targetDomainObject.getClass( ).getSimpleName( );
        }
        return hasPrivilege( authentication, targetType, permission.toString( ) );
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        if ( authentication == null || targetType == null || !( permission instanceof String ) ) {
            return false;
        }
        return hasPrivilege( authentication, targetType, permission.toString( ).toLowerCase( ) );
    }

    private boolean hasPrivilege( Authentication authentication, String targetType, String permission ) {
        Object principal = authentication.getPrincipal( );
        if ( principal instanceof Jwt) {
            for ( String grantedAuthority : Optional.ofNullable( ( ( Jwt ) principal ).getClaimAsStringList( "authorities" ) ).orElse( emptyList( ) ) ) {
                logger.info( "{} Contains granted authority {}", authentication.getPrincipal( ), grantedAuthority );
                targetType = targetType.replace( "Representation", "" ).replace( "DTO", "" ).toLowerCase( );
                if ( grantedAuthority.startsWith( targetType ) && grantedAuthority.contains( permission ) ) {
                    return true;
                }
            }
        }

        return false;
    }
}
